import {nanoid} from "nanoid";
import processVersionContentApi from '@/api/process/processVersionContentApi'
import {mergeStepConfigToFrontFile} from '@/utils'
import downloadUtil from '@/utils/downloadUtil'
import {message} from 'ant-design-vue'

const NODE_SPACE_Y = 120 // 节点纵向距离


export const customMountFunc = (lf) => {
	lf.removeNode = (nodeId) => {
		lf.deleteNode(nodeId);
	}
	lf.removeEdge = (edgeId) => {
		lf.deleteEdge(edgeId);
	}

	lf.disableEdge = (edgeId) => {
		//lf.deleteEdge(edgeId);
		const ls = lf.getEdgeModelById(edgeId)
		let props = ls.getProperties();
		props.disabled = true;
		ls.setProperties(props);
	}


	lf.enableEdge = (edgeId) => {
		//lf.deleteEdge(edgeId);
		const ls = lf.getEdgeModelById(edgeId)
		let props = ls.getProperties();
		props.disabled = false;
		ls.setProperties(props);
	}
	lf.copyNode = (nodeId) => {
		const data = lf.getNodeModelById(nodeId);
		let x = 0, y = 0
		x = data.x
		y = data.y + NODE_SPACE_Y;

		const newNodeData = {
			type: data.type, text: data.text.value, id: nanoid(5), properties: {
				component: data.properties.component
			}, x, y
		}
		lf.addNode(newNodeData);
	}
	/**
	 * 生成一条新逻辑的起点
	 */
	lf.genStartPos = () => {
		const bound = lf.getBoundRect()
		const x = GRAPH_START_X
		const y = bound.maxY === Infinity ? GRAPH_START_Y : bound.maxY + NODE_SPACE_Y
		return {x, y}
	}
	/**
	 * 获取当前图形所有节点的边界
	 */
	lf.getBoundRect = () => {
		const data = lf.getGraphData()
		const {nodes} = data
		const maxX = nodes.reduce((val, node) => {
			return Math.max(val, node.x)
		}, 0)
		const maxY = nodes.reduce((val, node) => {
			return Math.max(val, node.y)
		}, 0)
		const minX = nodes.reduce((val, node) => {
			return Math.min(val, node.x)
		}, Infinity)
		const minY = nodes.reduce((val, node) => {
			return Math.min(val, node.y)
		}, Infinity)
		return {minX, minY, maxX, maxY}
	}
	lf.closest = (el, selector) => {
		const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;

		while (el) {
			if (matchesSelector.call(el, selector)) {
				return el;
			} else {
				el = el.parentElement;
			}
		}
		return null;
	}
	lf.renderFile = async (file) => {

		//先render空的，再从后端查询
		lf.render([]);

		if (file) {
			console.log(file)
			lf.render(file);
			return
		}

		let d = await processVersionContentApi.getById({id: lf.id})
		if (!d) {
			d = {}
		}
		//设置版本号
		lf.version = d.processVersion;
		lf.processId = d.processId;
		lf.processName = d.processName;
		//设置前端资源文件
		if (d.frontFile) {
			d.frontFile = JSON.parse(d.frontFile);
		}
		lf.render(d.frontFile || []);
		//居中
		// lf.translateCenter()
	}

	lf.removeBuffById = (id) => {
		if (!lf.getNodeModelById) {
			return
		}
		var nodeModelById = lf.getNodeModelById(id);
		if (!nodeModelById) {
			return
		}
		let props = nodeModelById.getProperties();
		props.buffs = [];
		nodeModelById.setProperties(props);
	};


	lf.removeBuffNameById = (id, name) => {
		var nodeModelById = lf.getNodeModelById(id);

		let props = nodeModelById.getProperties();

		if (props.buffs && props.buffs.length > 0) {
			let tempBuffs = [];
			for (const buff of props.buffs) {
				if (buff.type != name) {
					tempBuffs.push(buff);
				}
			}
			props.buffs = tempBuffs;
		}
		nodeModelById.setProperties(props);
	}

	lf.removeBuffNameAll = (name) => {
		const graphData = lf.getGraphData();
		for (const node of graphData.nodes) {
			lf.removeBuffNameById(node.id, name);
		}
	};

	lf.hasContainsBuffByIdAndName = (id, name) => {
		var nodeModelById = lf.getNodeModelById(id);

		let props = nodeModelById.getProperties();
		let hasContainsBuffFlag = false;
		if (props.buffs && props.buffs.length > 0) {

			for (const buff of props.buffs) {
				if (buff.type == name) {
					hasContainsBuffFlag = true;
					break;
				}
			}

		}
		return hasContainsBuffFlag;
	}

	lf.getNodeBuffByName = (name) => {
		const graphData = lf.getGraphData();
		let resultNodeIds = [];
		for (const node of graphData.nodes) {
			let hasContainsBuffFlag = lf.hasContainsBuffByIdAndName(node.id, name);
			if (hasContainsBuffFlag) {
				resultNodeIds.push(node.id)
			}
		}
		return resultNodeIds;
	}

	lf.removeBuffAll = () => {
		const graphData = lf.getGraphData();
		for (const node of graphData.nodes) {
			lf.removeBuffById(node.id);
		}
	};


	//checkError
	lf.addBuffById = (id, buff, text) => {

		if (!lf.getNodeModelById) {
			return
		}
		lf.removeBuffById(id);

		let nodeModelById = lf.getNodeModelById(id);
		if (!nodeModelById) {
			return
		}
		let props = nodeModelById.getProperties();
		props.buffs.push({
			type: buff, text: text
		});
		nodeModelById.setProperties(props);
	};


	lf.addBuffAll = (buff, text) => {

		const graphData = lf.getGraphData();
		for (const node of graphData.nodes) {
			addBuffById(node.id, buff, text);
		}
	}
	lf.getNodeOutEdgeCode = (id) => {
		let nodeModelById = lf.getNodeModelById(id);
		return nodeModelById.getNodeOutEdgeCode();
	}

	lf.saveComponentConfig = (id, basicConfig, componentConfig) => {
		let nodeModelById = lf.getNodeModelById(id);
		let props = nodeModelById.getProperties();
		props.basicConfig = basicConfig
		props.componentConfig = componentConfig
		nodeModelById.setProperties(props);

		const edgeModels = lf.getNodeOutgoingEdge(id);
		if (edgeModels && edgeModels.length > 0) {
			for (let edgeModel of edgeModels) {
				if (edgeModel.render) {
					edgeModel.render();
				}
				//edgeModel.setProperties("c", "");
			}
		}

	}
	lf.setStepBuff = (stepStatusList) => {
		for (let stepStatus of stepStatusList) {

			//初始化
			if (stepStatus.stepExecutionStatus == "STATUS_PAUSED") {
				lf.removeBuffById(stepStatus.stepName);
				lf.addBuffById(stepStatus.stepName, "pause", "暂停中");
				continue;
			}

			//初始化
			if (stepStatus.stepExecutionStatus == "STATUS_IDLE") {
				lf.removeBuffById(stepStatus.stepName);
				lf.addBuffById(stepStatus.stepName, "stepInit");
				continue;
			}


			if (stepStatus.stepExecutionStatus == "STATUS_RUNNING") {
				lf.removeBuffById(stepStatus.stepName);
				lf.addBuffById(stepStatus.stepName, "stepRunning");
				continue;
			}

			if (stepStatus.stepExecutionStatus == "STATUS_FINISHED" || stepStatus.stepExecutionStatus == "STATUS_STOPPED" || stepStatus.stepExecutionStatus == "STATUS_HALTING") {
				if (stepStatus.errors > 0) {
					lf.removeBuffById(stepStatus.stepName);
					lf.addBuffById(stepStatus.stepName, "stepError");
				} else {
					if (stepStatus.linesRead > 0) {
						lf.removeBuffById(stepStatus.stepName);
						lf.addBuffById(stepStatus.stepName, "stepSuccess");
					} else {
						// debugger
						lf.removeBuffById(stepStatus.stepName);
						lf.addBuffById(stepStatus.stepName, "stepNoExecute");
					}
				}
			}
		}
	}
	lf.addStepLogById = (nodeId, logs) => {
		if (!lf.getNodeModelById) {
			return
		}
		let nodeModelById = lf.getNodeModelById(nodeId);
		if (!nodeModelById) {
			return
		}
		let props = nodeModelById.getProperties();

		if (!props.logs) {
			props.logs = []
		}
		props.logs.push({
			text: logs
		});
		nodeModelById.setProperties(props);
	}
	lf.removeStepLogById = (nodeId) => {
		var nodeModelById = lf.getNodeModelById(nodeId);
		if (!nodeModelById) {
			return
		}
		let props = nodeModelById.getProperties();
		props.logs = null;
		nodeModelById.setProperties(props);
	}


	lf.removeStepLogAll = () => {
		const graphData = lf.getGraphData();
		for (const node of graphData.nodes) {
			lf.removeStepLogById(node.id);
		}
	}

	lf.removeDataFlowById = (nodeId) => {
		var nodeModelById = lf.getNodeModelById(nodeId);
		if (!nodeModelById) {
			return
		}
		let props = nodeModelById.getProperties();
		props.dataFlow = null;
		nodeModelById.setProperties(props);
	}


	lf.removeDataFlowAll = () => {
		const graphData = lf.getGraphData();
		for (const node of graphData.nodes) {
			lf.removeDataFlowById(node.id);
		}
	}
	lf.removeChildLogDataById = (nodeId) => {
		var nodeModelById = lf.getNodeModelById(nodeId);
		if (!nodeModelById) {
			return
		}
		let props = nodeModelById.getProperties();
		props.childLogData = null;
		nodeModelById.setProperties(props);
	}
	lf.removeChildLogDataAll = () => {
		const graphData = lf.getGraphData();
		for (const node of graphData.nodes) {
			lf.removeChildLogDataById(node.id);
		}
	}
	lf.addDataFlowInputById = (nodeId, data) => {
		if (!lf.getNodeModelById) {
			return
		}
		let nodeModelById = lf.getNodeModelById(nodeId);
		if (!nodeModelById) {
			return
		}
		let props = nodeModelById.getProperties();

		if (!props.dataFlow) {
			props.dataFlow = {};
		}
		if (!props.dataFlow.input) {
			props.dataFlow.input = [];
		}
		props.dataFlow.input.push(data);
		nodeModelById.setProperties(props);

	}

	lf.addDataFlowOutputById = (nodeId, data) => {
		if (!lf.getNodeModelById) {
			return
		}
		let nodeModelById = lf.getNodeModelById(nodeId);
		if (!nodeModelById) {
			return
		}
		let props = nodeModelById.getProperties();

		if (!props.dataFlow) {
			props.dataFlow = {};
		}
		if (!props.dataFlow.output) {
			props.dataFlow.output = [];
		}

		props.dataFlow.output.push(data);
		nodeModelById.setProperties(props);
	}
	lf.getDataToSave = () => {
		const data = lf.getGraphData()

		let result = {...data};

		result.nodes.forEach((node, index) => {
			delete node.properties.dataFlow;
			delete node.properties.logs;
			delete node.properties.buffs;
			delete node.properties.childLogData;
		});
		return result;
	}

	lf.getFrontFile = (nodeId, componentConfig, basicConfig) => {
		const graphData = lf.getGraphData();
		let frontFile = mergeStepConfigToFrontFile(graphData, nodeId, componentConfig, basicConfig)
		return frontFile;

	}

	lf.resultTransfer = (d) => {
		if (d.data != null && typeof d.data == 'string') {
			try {
				d = {
					data: d.data ? JSON.parse(d.data) : null, type: d.type
				}
			} catch (e) {
				d = {
					data: d.data, type: d.type
				}
			}
		}
		return d
	}
	lf.clearBuffs = () => {
		lf.removeBuffAll()
		lf.removeStepLogAll()
		lf.removeDataFlowAll()
		lf.removeChildLogDataAll()
	}

	lf.logAndStepStatusFormat = (d) => {
		let data = lf.resultTransfer(d)

		if (!data) {
			return
		}
		if (!data.data) {
			return
		}

		if (data.type == 'result') {
			return data.data
		}
		data = data.data
		if (typeof data == 'string') {
			return data
		}
		//子组件的，直接设置到properties里面，当前节点不做处理
		if (!lf.isCurrentProcessLog(data)) {
			lf.setChildLogAndStepStatus(data);
			return;
		}
		let message = data.message
		let processVersion = data.processVersion || ''
		let threadId = data.threadId || ''
		let threadName = data.threadName || ''
		let timestamp = data.timestamp || ''
		let processName = data.processName || ''
		let logLevel = data.logLevel || ''
		let stepName = data.stepName || ''


		try {
			if (data.stepStatus && data.stepStatus.length > 0) {
				lf.setStepBuff(data.stepStatus)
				return ''
			}

			if (data.input) {
				if (typeof data.input != 'object') {
					data.input = {
						args0: data.input
					}
				}
				lf.addDataFlowInputById(stepName, data.input)
				return ''
			}
			//如果输出的不是对象，需要转成对象不然会出问题
			if (data.output) {
				if (typeof data.output != 'object') {
					data.output = {
						args0: data.output
					}
				}
				lf.addDataFlowOutputById(stepName, data.output)
				//props.stepOutput(stepName, data.output)
				return ''
			}
		} catch (e) {
			return message
		}

		let str = ''
		if (threadId && threadId != '') {
			str = `${threadId} - ${threadName} - ${timestamp} - ${processName} - ${processVersion} - ${logLevel} - ${stepName} - ${message}`
		} else {
			str = `${message}`
		}
		if (stepName && stepName != '') {
			lf.addStepLogById(stepName, str)
		}
		return str
	}

	lf.findCurrentProcessStepCode = (parent, stepCode) => {
		if (!parent) {
			return stepCode
		}
		let isCurrentProcessLog = lf.isCurrentProcessLog({
			stepName: parent.stepCode,
			processId: parent.processId,
			processVersion: parent.processVersion
		});

		if (isCurrentProcessLog) {
			return parent.stepCode;
		}

		if (parent.parent) {
			return lf.findCurrentProcessStepCode(parent.parent, stepCode);
		}
		return stepCode;
	}

	lf.isCurrentProcessLog = (data) => {
		if (!lf.getGraphData) {
			return true;
		}
		let stepCode = data.stepName;
		let isProcess = data.processId == lf.processId && data.processVersion == lf.version;
		if (stepCode) {
			const graphData = lf.getGraphData();
			let find = false;
			for (let node of graphData.nodes) {
				if (node.id == stepCode) {
					find = true;
					break
				}
			}
			if (find && isProcess) {
				return true;
			} else {
				return false;
			}
		}
		return isProcess;
	}

	lf.setChildLogAndStepStatus = (data) => {
		let nodeId = lf.findCurrentProcessStepCode(data.parent, null)
		if (!nodeId) {
			return
		}
		let nodeModelById = lf.getNodeModelById(nodeId);
		if (!nodeModelById) {
			return
		}
		let props = nodeModelById.getProperties();

		if (!props.childLogData) {
			props.childLogData = [];
		}

		data = {
			...data
		}
		props.childLogData.push(data);
		nodeModelById.setProperties(props);
	}

	lf.exportFile = async (key) => {
		if (key == 'json') {
			let json = lf.getDataToSave();
			downloadUtil.downloadFile(JSON.stringify(json, null, 2), lf.processName + '.json', 'text/plain')
		} else if (key == 'image') {
			//todo 未实现
			lf.getSnapshot('流程图', {
				fileType:'svg'
				// 注意：svg格式暂不支持width、height、backgroundColor、padding属性
			  });
		}
	}
}
